﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Infrastructure.ObjectModel.Screens;
using Infrastructure.ObjectModel;
using B10_Ex02_Elad_034695114_Meyron_026607788.ObjectModel;
using Microsoft.Xna.Framework;
using B10_Ex02_EladLebovitch_034695114.ObjectModel;
using Infrastructure.Managers;
using Microsoft.Xna.Framework.Input;
using B10_Ex02_Elad_034695114_Meyron_026607788;
using Infrastructure.ServiceInterfaces;

namespace B10_Ex02_EladLebovitch_034695114.Screens
{
    public class MainGameScreen : GameScreen
    {
        #region Consts
        private const int k_MotherShipInterval = 15000;
        private const int k_EnemyRows = 5;
        private const int k_EnemyCols = 9;
        private const int k_FirstPlayerNumber = 1;
        private const int k_SecondPlayerNumber = 2;
        private const int k_StartingSouls = 3;
        private const int k_BarriersCount = 4;
        private const int k_LevelCycles = 4;
        #endregion

        #region Data members
        private double m_MotherShipTime;
        private EnemyMatrix m_EnemiesMat;
        private BarrierLine m_BarrierLine;
        private MotherShip m_CurrMothership;
        private HumanPlayer m_humPlayerOne;
        private HumanPlayer m_humPlayerTwo;
        private GameStatusDisplay m_gameDisplay;
        private ICollisionsManager m_MyCollisionDetector;
        private List<ObjectPair> m_arrBulletCollisions;

        private GameFlow GameFlowData
        {
            get;
            set;
        }

        public bool IsGameOver
        {
            get;
            set;
        }

        public MainGameScreen(Game i_Game)
            : base(i_Game)
        {
        }

        #endregion

        #region Methods
        /// <summary>
        /// Init method
        /// </summary>
        public override void Initialize()
        {
            // Init stuff
            base.Initialize();

            this.IsGameOver = false;
            this.GameFlowData = (this.Game.Services.GetService(typeof(GameFlow)) as GameFlow);

            // Get collision detector
            m_MyCollisionDetector = this.Game.Services.GetService(typeof(ICollisionsManager)) as ICollisionsManager;

            // Set bullet collision keeper
            m_arrBulletCollisions = new List<ObjectPair>();

            // Create game objcets
            m_EnemiesMat = new EnemyMatrix(this.Game, k_EnemyCols + ((GameFlowData.CurrentLevel - 1) % k_LevelCycles), k_EnemyRows);
            this.Add(m_EnemiesMat);
            m_EnemiesMat.MatrixEnemyDied += new EnemyDestroyed(this.enemeyDestroyed);
            m_BarrierLine = new BarrierLine(this.Game, k_BarriersCount);
            // this.Add(m_BarrierLine);

            // Create the players and space ship
            m_humPlayerOne = new HumanPlayer(this.Game, Keys.Left, Keys.Right, Keys.Enter,
                                           k_FirstPlayerNumber, k_FirstPlayerNumber - 1, true);
            InitPlayer(m_humPlayerOne, GameFlowData.PlayerOneScore);

            // Check if we are two players
            if (GameFlowData.IsTwoPlayers)
            {
                m_humPlayerTwo = new HumanPlayer(this.Game, Keys.A, Keys.D, Keys.Space,
                                       k_SecondPlayerNumber, k_SecondPlayerNumber - 1, false);
                InitPlayer(m_humPlayerTwo, GameFlowData.PlayerTwoScore);
            }
            
            // Game status display
            m_gameDisplay = new GameStatusDisplay(this.Game, m_humPlayerOne, m_humPlayerTwo,
                                                  Microsoft.Xna.Framework.Graphics.Color.Blue,
                                                  Microsoft.Xna.Framework.Graphics.Color.Green);
            this.Add(m_gameDisplay);

            // Set the background
            InvadorBackground ibgCurr = new InvadorBackground(this.Game, @"Sprites\BG_Space01_1024x768");
            this.Add(ibgCurr);

            // Handle the mother ship appearence
            this.m_MotherShipTime = 0;
        }

        /// <summary>
        /// Sets the player init stuff
        /// </summary>
        /// <param name="io_humPlayer">the current player</param>
        private void InitPlayer(HumanPlayer io_humPlayer, int i_GameScore)
        {
            io_humPlayer.Souls = k_StartingSouls;
            io_humPlayer.GameScore = i_GameScore;
            io_humPlayer.PlayerIsDeadEvent += new EventHandler(humPlayer_PlayerIsDeadEvent);
            this.Add(io_humPlayer.PlayerShip);
        }

        /// <summary>
        /// What happens when a player is out of souls
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void humPlayer_PlayerIsDeadEvent(object sender, EventArgs e)
        {
            // Check if one of the players is still alive
            if (GameFlowData.IsTwoPlayers)
            {
                if (m_humPlayerOne.Souls <= 0 && m_humPlayerTwo.Souls <= 0)
                {
                    gameOver();
                }
            }
            else if (m_humPlayerOne.Souls <= 0)
            {
                gameOver();
            }
        }

        /// <summary>
        /// Handles checks of the matrix
        /// </summary>
        private void handleMatrix()
        {
            // if the matrix got lower then spaceship
            if (this.m_EnemiesMat.LowerBoundery >= this.m_humPlayerOne.PlayerShip.PositionOfOrigin.Y)
            {
                this.gameOver();
            }
        }

        /// <summary>
        /// The mothership creation method
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void handleMotherShip(GameTime gameTime)
        {
            this.m_MotherShipTime += gameTime.ElapsedGameTime.TotalMilliseconds;

            // Create a new mother ship
            if (this.m_MotherShipTime >= k_MotherShipInterval)
            {
                // if there is the first ship, Register it
                if (this.m_CurrMothership == null)
                {
                    // Create and register new
                    this.m_CurrMothership = new MotherShip(this.Game);
                    this.Add(m_CurrMothership);
                    this.m_MotherShipTime -= k_MotherShipInterval;
                    this.m_MyCollisionDetector.AddObjectToMonitor(this.m_CurrMothership);
                    this.m_CurrMothership.Destroyed += new EnemyDestroyed(enemeyDestroyed);
                }
                else
                {
                    this.m_CurrMothership.Initialize();
                }
            }
        }

        /// <summary>
        /// When an enemy is dead, if it's the last one then game over
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void enemeyDestroyed(object sender, EventArgs e)
        {
            // Check if this was the last enemy
            if (m_EnemiesMat.EnemiesList.Count <= 0)
            {
                gameOver();
            }
        }

        /// <summary>
        /// When we won or lost
        /// </summary>
        private void gameOver()
        {
            this.IsGameOver = true;
            string strWinner = string.Empty;
            string strPlayerTwoScore = string.Empty;

            // If the players won? 
            if (m_EnemiesMat.EnemiesList.Count == 0)
            {
                GameFlowData.PlayerOneScore = this.m_humPlayerOne.GameScore;

                // Check if two players
                if (GameFlowData.IsTwoPlayers)
                {
                    GameFlowData.PlayerTwoScore = this.m_humPlayerTwo.GameScore;
                }

                (Game.Services.GetService(typeof(ISoundManeger)) as ISoundManeger).PlayCue("LevelWin");

                GameFlowData.NextLevel();
            }
            else
            {
                // Check who won
                if (GameFlowData.IsTwoPlayers)
                {
                    strPlayerTwoScore = "\n Player Two Score: " + m_humPlayerTwo.GameScore.ToString();

                    if (m_humPlayerOne.GameScore > m_humPlayerTwo.GameScore)
                    {
                        strWinner = "Player one WINS!";
                    }
                    else if (m_humPlayerOne.GameScore < m_humPlayerTwo.GameScore)
                    {
                        strWinner = "Player two WINS!";
                    }
                    else
                    {
                        strWinner = "It is a TIE!";
                    }
                }
                else
                {
                    strWinner = "You had no competition!";
                }

                // Notfiy the user
                (Game.Services.GetService(typeof(ISoundManeger)) as ISoundManeger).PlayCue("GameOver");
                ScreensManager.SetCurrentScreen(new GameOverScreen(this.Game, "Player One Score: " + m_humPlayerOne.GameScore.ToString() +
                                                     strPlayerTwoScore +
                                                     "\n" + strWinner));
                this.ExitScreen();
            }
        }

        /// <summary>
        /// Update method for calcing the game
        /// </summary>
        /// <param name="gameTime"></param>
        public override void Update(GameTime gameTime)
        {
            // TODO: Delete Debug for game over
            if (InputManager.KeyPressed(Keys.G))
            {
                gameOver();
            }
            else if (InputManager.KeyPressed(Keys.Q))
            {
                foreach (EnemySprite item in m_EnemiesMat.EnemiesList)
                {
                    item.Collided(new PlayerBullet(this.Game, Vector2.Zero));
                }
            }
            else if (this.InputManager.KeyPressed(Keys.M))
            {
                (Game.Services.GetService(typeof(ISoundManeger)) as ISoundManeger).ToggleMute();
            }

            if (!IsGameOver)
            {
                // Make sure there is a need for update
                if (InputManager.KeyPressed(Keys.P))
                {
                    ScreensManager.SetCurrentScreen(new PauseScreen(this.Game));
                }

                // Handle both componentes
                this.handleMotherShip(gameTime);
                this.handleMatrix();

                base.Update(gameTime);
            }
        }
        #endregion
    }
}
